/**
 * Copyright (c) 2011 Ibrahim Abd Elkader <i.abdalkader@gmail.com> 
 * See the file COPYING for copying permission.
 */
#include <stdio.h>
#include <lpc17xx_ssp.h>
#include <lpc17xx_gpio.h>
#include <lpc17xx_pinsel.h>
#include "nrf24l01p.h"
/* SSP config */
#define SSP_BASE            (LPC_SSP0)  /* SSP 0*/
#define SSP_PORT            (0)         /* SSP PORT0*/
#define SSP_MOSI            (18)        /* SSP MOSI*/
#define SSP_MISO            (17)        /* SSP MISO*/
#define SSP_CSN             (16)        /* SSP SSEL*/
#define SSP_SCLK            (15)        /* SSP SCLK*/
#define SSP_CLCK            (12500000)  /* 12.5 Mhz*/
/* GPIO config */
#define GPIO_PORT           (2)         /* GPIO port  */
#define CE                  (6)         /* chip enable*/
#define IRQ                 (24)        /* IRQ        */
#define INT_RISING          (0)
#define INT_FALLING         (1)
/* nrf commands */
#define R_REGISTER          (0x00)      /* read register     */
#define W_REGISTER          (0x20)      /* write register    */
#define R_RX_PAYLOAD        (0x61)      /* read RX payload   */
#define W_TX_PAYLOAD        (0xA0)      /* write TX payload  */
#define FLUSH_TX            (0xE1)      /* flush TX FIFO     */
#define FLUSH_RX            (0xE2)      /* flush RX FIFO     */
/* registers definitions */
#define CONFIG              (0x00)      /* configuration        */
#define EN_AA               (0x01)      /* enable automatic ACL */
#define EN_RXADDR           (0x02)      /* enable RX addresses  */
#define SETUP_AW            (0x03)      /* setup address width  */
#define SETUP_RETR          (0x04)      /* setup retransmission */
#define RF_CH               (0x05)      /* RF channel           */
#define RF_SETUP            (0x06)      /* RF setup             */
#define STATUS              (0x07)      /* status register      */
#define OBSERVE_TX          (0x08)      /* TX observe           */
#define RPD                 (0x09)      /* received power detector     */
#define RX_ADDR_P0          (0x0A)      /* receive address data pipe 0 */
#define RX_ADDR_P1          (0x0B)      /* receive address data pipe 1 */
#define RX_ADDR_P2          (0x0C)      /* receive address data pipe 2 */
#define RX_ADDR_P3          (0x0D)      /* receive address data pipe 3 */
#define RX_ADDR_P4          (0x0E)      /* receive address data pipe 4 */
#define RX_ADDR_P5          (0x0F)      /* receive address data pipe 5 */
#define TX_ADDR             (0x10)      /* transmit address            */
#define RX_PW_P0            (0x11)      /* number of bytes in RX payload in data pipe 0 */
#define RX_PW_P1            (0x12)      /* number of bytes in RX payload in data pipe 1 */
#define RX_PW_P2            (0x13)      /* number of bytes in RX payload in data pipe 2 */
#define RX_PW_P3            (0x14)      /* number of bytes in RX payload in data pipe 3 */
#define RX_PW_P4            (0x15)      /* number of bytes in RX payload in data pipe 4 */
#define RX_PW_P5            (0x16)      /* number of bytes in RX payload in data pipe 5 */
#define FIFO_STATUS         (0x17)      /* FIFO status */
#define DYNPD               (0x1C)      /* enable dynamic payload length */
/* CONFIG register bits */
#define PRIM_RX             (1<<0)
#define PWR_UP              (1<<1)
#define CRCO                (1<<2)
#define EN_CRC              (1<<3)
#define MASK_MAX_RT         (1<<4)
#define MASK_TX_DS          (1<<5)
#define MASK_RX_DR          (1<<6)
/* STATUS register bits */
#define ST_TX_FULL          (1<<0)
#define MAX_RT              (1<<4)
#define TX_DS               (1<<5)
#define RX_DR               (1<<6)
/* FIFO Status register */
#define RX_EMPTY            (1<<0)
#define RX_FULL             (1<<1)
#define TX_EMPTY            (1<<4)
#define TX_FULL             (1<<5)
#define TX_REUSE            (1<<6)
/* EN_RXADDR */
#define ERX_P0              (1<<0)
#define ERX_P1              (1<<1)
#define ERX_P2              (1<<2)
#define ERX_P3              (1<<3)
#define ERX_P4              (1<<4)
#define ERX_P5              (1<<5)
/* powerdown to standby transition time */
#define TPD2STBY            (5/*ms*/) 
#define CSN_LO()            FIO_ClearValue(SSP_PORT, (1<<SSP_CSN))
#define CSN_HI()            FIO_SetValue(SSP_PORT,   (1<<SSP_CSN))
#define CE_LO()             FIO_ClearValue(GPIO_PORT, (1<<CE))
#define CE_HI()             FIO_SetValue(GPIO_PORT,   (1<<CE))
uint8_t ssp_read_byte()
{
    while(SSP_GetStatus(SSP_BASE, SSP_STAT_BUSY));
    SSP_SendData(SSP_BASE, 0xFF);
    while(SSP_GetStatus(SSP_BASE, SSP_STAT_BUSY));
    return SSP_ReceiveData(SSP_BASE);
}

uint8_t ssp_write_byte(uint8_t w)
{
    SSP_SendData(SSP_BASE, w);    
    while(SSP_GetStatus(SSP_BASE, SSP_STAT_BUSY));
    /* STATUS register byte ignored*/
    return SSP_ReceiveData(SSP_BASE); 
}

void nrf_cmd(uint8_t cmd)
{
    CSN_LO();
    ssp_write_byte(cmd);
    CSN_HI();
}

uint8_t nrf_read_reg(uint8_t reg)
{
    CSN_LO();
    ssp_write_byte(R_REGISTER|reg);
    reg = ssp_read_byte(); 
    CSN_HI();
    return reg;
}

void nrf_write_reg(uint8_t reg, uint8_t dat)
{
    CSN_LO();
    ssp_write_byte(W_REGISTER|reg);
    ssp_write_byte(dat);
    CSN_HI();
}

void nrf_clr_int()
{
    uint8_t st;
    st = nrf_read_reg(STATUS);
    /* clears pending interrupts */
    nrf_write_reg(STATUS, (st | 0x70));  
}

void nrf_init()
{
    PINSEL_CFG_Type pin_cfg={
        .Funcnum    = 2,
        .Portnum    = SSP_PORT,
        .Pinmode    = PINSEL_PINMODE_PULLUP,
        .OpenDrain  = PINSEL_PINMODE_NORMAL,
    };
    
    SSP_CFG_Type  ssp_cfg ={
        .CPHA           = 0,
        .CPOL           = 0,
        .ClockRate      = SSP_CLCK,
        .Databit        = SSP_DATABIT_8,
        .Mode           = SSP_MASTER_MODE,
        .FrameFormat    = SSP_FRAME_SPI
    };

    /*SSP PINSEL configuration*/
    pin_cfg.Pinnum = SSP_MOSI;
    PINSEL_ConfigPin(&pin_cfg);

    pin_cfg.Pinnum = SSP_MISO;
    PINSEL_ConfigPin(&pin_cfg);

    pin_cfg.Pinnum = SSP_SCLK;
    PINSEL_ConfigPin(&pin_cfg);

    SSP_Init(SSP_BASE, &ssp_cfg);
    SSP_Cmd(SSP_BASE, ENABLE);

    /*use FIO for CE and CSN*/
    FIO_SetMask(SSP_PORT,  (1<<SSP_CSN), 0);
    FIO_SetDir(SSP_PORT,   (1<<SSP_CSN), 1);

    FIO_SetMask(GPIO_PORT, (1<<CE), 0);
    FIO_SetDir(GPIO_PORT,  (1<<CE), 1);

    FIO_ClearValue(GPIO_PORT, (1<<CE));
    FIO_SetValue(GPIO_PORT, (1<<SSP_CSN));

    sleep(100);/*power on reset*/
    nrf_write_reg(CONFIG, 0x00); /*power down*/
    nrf_cmd(FLUSH_TX);
    nrf_cmd(FLUSH_RX);
    nrf_clr_int();
    /*set RF output power*/
    nrf_write_reg(RF_SETUP, 0x08);  /*2Mbps|0dBm*/
    nrf_write_reg(EN_AA, 0x00);       /*disable auto-ack*/
    nrf_write_reg(SETUP_RETR, 0x00);  /*disable re-transmit*/
    nrf_write_reg(EN_RXADDR, ERX_P0); /*enable pipe 0*/
    nrf_write_reg(RX_PW_P0, 32);
    /*power up*/
    nrf_write_reg(CONFIG, (MASK_TX_DS|MASK_RX_DR|MASK_MAX_RT|PWR_UP));
    sleep(TPD2STBY);

    /*should now enter standby mode*/
    printf("nrf: 0x%x\n", nrf_read_reg(CONFIG)); 
}

void nrf_tx_mode()
{
    uint8_t config = nrf_read_reg(CONFIG);  /*read CONFIG*/
    nrf_write_reg(CONFIG, (config & ~PRIM_RX));/*set PRIM_RX low*/
    CE_HI();
    sleep(1);
}

void nrf_rx_mode()
{
    uint8_t config = nrf_read_reg(CONFIG);  /*read CONFIG*/
    nrf_write_reg(CONFIG, (config | PRIM_RX));/*set PRIM_RX low*/  
    sleep(1);
}

void delay_us(int t) 
{
    int i = 0;
    while (--t) {
        for(i=0; i<500; ++i) {
            asm("nop");
        }
    }
}

void nrf_send(uint8_t *buf, int len)
{
    int i=0;
    while (i<len) {    
        CSN_LO();
        /*load TX FIFO*/
        ssp_write_byte(W_TX_PAYLOAD); 
        do {
            ssp_write_byte(buf[i++]);
        }while (i%32 !=0);
        CSN_HI();
        delay_us(30);
        while (!(nrf_read_reg(STATUS) & TX_DS));
        /*clear pending interrupts*/
        nrf_write_reg(STATUS, 0x70); 
    }
}

void nrf_recv(uint8_t *buf, int len)
{
    int i = 0;
    while (i<len) {
        //PRX mode
        CE_HI(); 
        //wait for packet
        while (!(nrf_read_reg(STATUS) & RX_DR));
        CE_LO();

        while (!(nrf_read_reg(FIFO_STATUS) & RX_EMPTY)) {
            CSN_LO();
            ssp_write_byte(R_RX_PAYLOAD);
            do {
                buf[i++] = ssp_read_byte();
            }while(i%32 !=0);
            CSN_HI();
       }
        //clear pending interrupts
        nrf_write_reg(STATUS, 0x70);    
    }
}
